import os
from PIL import Image, ImageTk
from glob import glob
import tkinter as tk
from tkinter import ttk, messagebox, simpledialog

# -------------------------- 可自定义配置 --------------------------
# 裁剪后图片的保存目录（相对于脚本所在目录）
OUTPUT_DIR = "裁剪结果"
# 支持的图片格式（可根据需要补充）
SUPPORTED_FORMATS = ("*.jpg", "*.jpeg", "*.png", "*.bmp", "*.gif", "*.webp")
# 是否覆盖已存在的裁剪后图片（True=覆盖，False=跳过）
OVERWRITE = True
# -------------------------------------------------------------------

def get_script_dir():
    """获取脚本所在的绝对目录"""
    return os.path.dirname(os.path.abspath(__file__))

class ImageCropper:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("交互式图片裁剪工具")
        self.root.geometry("800x600")
        
        # 初始化变量
        self.crop_values = [0, 0, 0, 0]  # top, bottom, left, right
        self.sample_image_path = None
        self.original_image = None
        self.preview_image = None
        self.current_direction = 0  # 0:上, 1:下, 2:左, 3:右
        self.directions = ["上方", "下方", "左侧", "右侧"]
        
        # 创建界面
        self.create_widgets()
        
    def create_widgets(self):
        """创建界面组件"""
        # 主框架
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        # 标题
        title_label = ttk.Label(main_frame, text="交互式图片裁剪工具", 
                               font=("Arial", 16, "bold"))
        title_label.grid(row=0, column=0, columnspan=2, pady=(0, 20))
        
        # 图片信息
        self.info_label = ttk.Label(main_frame, text="请选择样本图片", 
                                   font=("Arial", 10))
        self.info_label.grid(row=1, column=0, columnspan=2, pady=(0, 10))
        
        # 图片显示区域框架
        image_frame = ttk.Frame(main_frame)
        image_frame.grid(row=2, column=0, columnspan=2, pady=10, sticky="nsew")
        
        # 图片显示标签 (使用tk.Label而不是ttk.Label)
        self.image_label = tk.Label(image_frame, background="lightgray", 
                                   width=60, height=20, 
                                   text="预览区域\n(等待加载图片)")
        self.image_label.pack(fill=tk.BOTH, expand=True)
        
        # 裁剪信息显示
        self.crop_info_label = ttk.Label(main_frame, text="裁剪设置: 上:0 下:0 左:0 右:0")
        self.crop_info_label.grid(row=3, column=0, columnspan=2, pady=5)
        
        # 按钮框架
        button_frame = ttk.Frame(main_frame)
        button_frame.grid(row=4, column=0, columnspan=2, pady=10)
        
        # 按钮
        self.start_button = ttk.Button(button_frame, text="开始裁剪设置", 
                                      command=self.start_crop_setup)
        self.start_button.pack(side=tk.LEFT, padx=5)
        
        ttk.Button(button_frame, text="应用裁剪到所有图片", 
                  command=self.apply_to_all).pack(side=tk.LEFT, padx=5)
        
        ttk.Button(button_frame, text="退出", 
                  command=self.root.quit).pack(side=tk.LEFT, padx=5)
        
        # 配置网格权重
        main_frame.columnconfigure(0, weight=1)
        main_frame.rowconfigure(2, weight=1)
        image_frame.columnconfigure(0, weight=1)
        image_frame.rowconfigure(0, weight=1)
    
    def find_sample_image(self):
        """查找样本图片"""
        script_dir = get_script_dir()
        image_files = []
        for fmt in SUPPORTED_FORMATS:
            image_files.extend(glob(os.path.join(script_dir, fmt)))
        
        if image_files:
            self.sample_image_path = image_files[0]
            try:
                self.original_image = Image.open(self.sample_image_path)
                self.update_preview()
                self.info_label.config(text=f"样本图片: {os.path.basename(self.sample_image_path)} "
                                          f"(尺寸: {self.original_image.width}×{self.original_image.height})")
                return True
            except Exception as e:
                messagebox.showerror("错误", f"无法打开图片: {str(e)}")
                return False
        else:
            messagebox.showerror("错误", "未找到任何图片文件")
            return False
    
    def start_crop_setup(self):
        """开始裁剪设置流程"""
        if not self.find_sample_image():
            return
        
        self.current_direction = 0
        self.ask_crop_direction()
    
    def ask_crop_direction(self):
        """询问是否裁剪当前方向"""
        if self.current_direction >= 4:
            messagebox.showinfo("完成", "所有方向的裁剪设置已完成！")
            return
        
        direction = self.directions[self.current_direction]
        result = messagebox.askyesno("裁剪设置", 
                                   f"是否需要裁剪{direction}区域？\n\n"
                                   f"当前裁剪设置:\n"
                                   f"上: {self.crop_values[0]}px, 下: {self.crop_values[1]}px\n"
                                   f"左: {self.crop_values[2]}px, 右: {self.crop_values[3]}px")
        
        if result:
            self.ask_crop_value()
        else:
            self.current_direction += 1
            self.ask_crop_direction()
    
    def ask_crop_value(self):
        """询问裁剪像素值"""
        direction = self.directions[self.current_direction]
        
        while True:
            value = simpledialog.askinteger("输入裁剪量", 
                                          f"请输入{direction}裁剪量（像素）:",
                                          parent=self.root,
                                          minvalue=0,
                                          initialvalue=self.crop_values[self.current_direction])
            
            if value is None:  # 用户点击取消
                self.current_direction += 1
                self.ask_crop_direction()
                return
            
            # 检查裁剪值是否有效
            if self.is_crop_valid(value):
                self.crop_values[self.current_direction] = value
                self.update_preview()
                self.show_preview_result()
                break
            else:
                messagebox.showerror("错误", "裁剪量过大，会导致图片尺寸为0或负数！")
    
    def is_crop_valid(self, new_value):
        """检查裁剪值是否有效"""
        temp_values = self.crop_values.copy()
        temp_values[self.current_direction] = new_value
        
        width = self.original_image.width - temp_values[2] - temp_values[3]  # left + right
        height = self.original_image.height - temp_values[0] - temp_values[1]  # top + bottom
        
        return width > 0 and height > 0
    
    def update_preview(self):
        """更新预览图"""
        if not self.original_image:
            return
        
        # 计算裁剪区域
        crop_box = (
            self.crop_values[2],  # left
            self.crop_values[0],  # top
            self.original_image.width - self.crop_values[3],  # right
            self.original_image.height - self.crop_values[1]  # bottom
        )
        
        # 裁剪图片
        try:
            self.preview_image = self.original_image.crop(crop_box)
            
            # 调整预览图大小以适应显示区域
            display_size = (400, 300)
            display_image = self.preview_image.copy()
            display_image.thumbnail(display_size, Image.Resampling.LANCZOS)
            
            # 转换为tkinter可显示的格式
            photo = ImageTk.PhotoImage(display_image)
            self.image_label.configure(image=photo)
            self.image_label.image = photo  # 保持引用
            self.image_label.configure(text="")  # 移除文本
            
            # 更新裁剪信息
            info_text = (f"裁剪设置: 上:{self.crop_values[0]}px 下:{self.crop_values[1]}px "
                        f"左:{self.crop_values[2]}px 右:{self.crop_values[3]}px\n"
                        f"原始尺寸: {self.original_image.width}×{self.original_image.height} | "
                        f"裁剪后尺寸: {self.preview_image.width}×{self.preview_image.height}")
            self.crop_info_label.config(text=info_text)
            
        except Exception as e:
            messagebox.showerror("错误", f"裁剪失败: {str(e)}")
    
    def show_preview_result(self):
        """显示裁剪结果并询问是否满意"""
        direction = self.directions[self.current_direction]
        
        result = messagebox.askyesno("预览结果", 
                                   f"{direction}裁剪效果已更新！\n\n"
                                   f"当前裁剪后尺寸: {self.preview_image.width}×{self.preview_image.height}\n\n"
                                   f"是否满意当前效果？",
                                   detail="选择'是'进入下一步，选择'否'重新调整")
        
        if result:
            self.current_direction += 1
            self.ask_crop_direction()
        else:
            self.ask_crop_value()  # 重新调整当前方向
    
    def apply_to_all(self):
        """将裁剪设置应用到所有图片"""
        if not all(v == 0 for v in self.crop_values):
            result = messagebox.askyesno("确认", 
                                       f"将应用当前裁剪设置到所有图片：\n"
                                       f"上:{self.crop_values[0]}px, 下:{self.crop_values[1]}px\n"
                                       f"左:{self.crop_values[2]}px, 右:{self.crop_values[3]}px\n\n"
                                       f"是否继续？")
            if not result:
                return
        else:
            messagebox.showinfo("提示", "裁剪量全部为0，无需处理")
            return
        
        script_dir = get_script_dir()
        output_dir = os.path.join(script_dir, OUTPUT_DIR)
        
        # 创建输出目录
        if not os.path.exists(output_dir):
            os.makedirs(output_dir)
        
        # 查找所有图片文件
        image_files = []
        for fmt in SUPPORTED_FORMATS:
            image_files.extend(glob(os.path.join(script_dir, fmt)))
        
        # 过滤掉输出目录中的图片
        image_files = [f for f in image_files if not f.startswith(output_dir)]
        
        if not image_files:
            messagebox.showinfo("完成", "未找到需要处理的图片")
            return
        
        # 批量处理
        success_count = 0
        for img_path in image_files:
            try:
                with Image.open(img_path) as img:
                    crop_box = (
                        self.crop_values[2],
                        self.crop_values[0],
                        img.width - self.crop_values[3],
                        img.height - self.crop_values[1]
                    )
                    
                    # 检查裁剪区域是否有效
                    if (crop_box[0] >= crop_box[2] or crop_box[1] >= crop_box[3]):
                        print(f"跳过无效裁剪: {os.path.basename(img_path)}")
                        continue
                    
                    cropped_img = img.crop(crop_box)
                    output_path = os.path.join(output_dir, os.path.basename(img_path))
                    
                    # 检查是否覆盖
                    if not OVERWRITE and os.path.exists(output_path):
                        continue
                    
                    cropped_img.save(output_path)
                    success_count += 1
                    
            except Exception as e:
                print(f"处理失败 {os.path.basename(img_path)}: {str(e)}")
        
        messagebox.showinfo("完成", f"批量处理完成！\n成功处理 {success_count}/{len(image_files)} 张图片\n\n输出目录: {output_dir}")
    
    def run(self):
        """运行应用程序"""
        self.root.mainloop()

def main():
    """主函数"""
    print("=====================================")
    print("     交互式图片裁剪工具 (图形界面)     ")
    print("=====================================")
    
    # 创建并运行应用程序
    app = ImageCropper()
    app.run()

if __name__ == "__main__":
    main()